home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr30
/
clockon.zip
/
CLOCKON.ASM
next >
Wrap
Assembly Source File
|
1993-05-07
|
26KB
|
708 lines
page 60,132
title 'CLOCKON'
;mode equ 0 ;mode = 0 for hh:mm only
mode equ -1 ;mode = -1 for hh:mm:ss
if mode eq 0
bytes equ 5 ;bytes in hh:mm time display
ticks equ 36 ;ticks between clock updates
else
bytes equ 8 ;bytes in hh:mm:ss time display
ticks equ 18 ;ticks between clock updates
endif
;
bel equ 07H
tab equ 09H
lf equ 0aH
cr equ 0dH
;beta equ 0e1H
beta equ ' '
;
;****************************************************************
;
;++++ START OF RESIDENT CODE
;
;****************************************************************
;
code segment
assume DS:code, SS:code ,CS:code ,ES:code
org 0080H
dbuff equ $
org 0100H
stack equ $
start:
jmp initialize
;
inst_msg db 'Clockon.HJH' ;identifier message (leave it here!)
msg_size equ $ - offset start
;
colour db 70h ;predefined clock colours
; ;lo nybble=F/G hi nybble=B/G
freq dw 00600H ;beep frequency
beep_length dw 40H ;beep length (modified by CLOCKON x)
;
max_alarms equ 9 ;never more than 9 - may be less
alarm_times dw max_alarms dup (0ffffH) ;alarm times
;
beep_count equ 10 ;predefined beep count
beeps db beep_count ;set beep counter
;
page_no db 0 ;current page number
no_display_flag db '+' ;'+' to enable, '-' to inhibit
last_hour dw 0 ;last hour - used to detect hour update
old_cursor dw 0 ;old cursor position
;
;
line_col equ 0050H - bytes ;starting line and column for display
clk_count dw ticks ;counts left to next update
hours dw 0 ;time ASCII store
db ':'
minutes dw 0
db ':'
seconds dw 0
;
old_SP dw 0 ;called SP
old_SS dw 0 ;called SS
oldint08 dd 0 ;original INT 08 vector
oldint10 dd 0 ;original INT 10 vector
bios_flag db 0 ;bios active flag
;=============================================================================
; VIDINT intercepts and handles the video interrupt 10H.
;=============================================================================
ASSUME CS:code, DS:nothing
vidint proc near
pushf ;simulate INT
inc CS:bios_flag ;bump flag
call CS:oldint10 ;call original function
dec CS:bios_flag ;decrement flag
iret
vidint endp
;
;----------------------------------------------------------------
;++++ Replaced INT 08 - used to detect when clock update needed
;
ASSUME CS:code, DS:code
newint08 proc near
push ax ;save ax
push DS ;and DS
pushf ;and flags
push CS ;set up DS to point
pop DS ;to CS
mov ax,clk_count ;get clock count
dec ax ;decrement by 1
jz int1 ;skip if reaches zero
mov clk_count,ax ;new value saved
jmp int8 ;quick exit
int1:
cli ;stop interrupts
mov ax,SS ;save SS and SP
mov old_SS,ax
mov old_SP,sp
mov ax,DS ;set SS to DS
mov SS,ax
mov sp,offset stack ;and create a new stack
sti ;restart interrupts
push bx ;save other regs
push cx
push dx
push ES
push si
push di
push bp
mov ax,ticks ;reset clock count
mov clk_count,ax
;
;++++ Check for the time
;
mov ah,0 ;read clock count
int 1AH ;returns clock count in CX:DX
;
;++++ The following code takes the clock count returned by INT 1Ah
; and:-
; (1) Multiplies by 16 by using repetitive shifts
; (ignores overflow at the high end and inserts zeros
; at the low end of DX:AX)
; (2) Divides by 17478 to convert to minutes
; (17478 = 60 * 18.2065 * 16)
;
mov ax,dx ;low time count to ax
mov dx,cx ;hi time count to dx
shl ax,1 ;multiply by 2
rcl dx,1 ;multiply by 2, add carry
shl ax,1 ;multiply by 2
rcl dx,1 ;multiply by 2, add carry
shl ax,1 ;multiply by 2
rcl dx,1 ;multiply by 2, add carry
shl ax,1 ;multiply by 2
rcl dx,1 ;multiply by 2, add carry
mov bx,04446h
div bx ;divide it by 17478
;AX=minutes DX=remainder
mov cx,max_alarms ;# alarms to test
xor bx,bx ;start at first alarm
alarm_loop:
call alarm_test
jz int3 ;quick exit if alarm was sounded
add bx,2
loop alarm_loop
int3:
call display_check ;see if display wanted
jc int4 ;continue if carry set
jmp int7 ;otherwise quick exit
int4:
mov seconds,dx ;set seconds to dx
mov bx,60 ;divisor = 60
xor dx,dx ;clear dx
div bx
mov minutes,dx ;set minutes to dx
cmp ax,0 ;test ax
aam ;adjust
cmp ax,last_hour ;see if hour has changed
jz int5
mov last_hour,ax ;update hour store
call beep ;and beep once
int5:
add ax,'00' ;make hours into ASCII
xchg ah,al
mov hours,ax ;save bytes
mov ax,minutes ;get minutes
aam ;adjust
add ax,'00'
xchg ah,al
mov minutes,ax ;and store
mov ax,seconds ;get seconds
xor dx,dx
mov bx,60
mul bx
mov bx,04446h
div bx
aam ;adjust
add ax,'00'
xchg ah,al
mov seconds,ax ;and store
mov ah,3
mov bh,page_no ;get page number
int 10H ;read cursor position
mov old_cursor,dx
mov ah,2
mov bh,page_no ;get page number
mov dx,line_col ;starting line/column
int 10H ;set cursor position
mov si,offset hours ;point to ASCII store
mov bl,colour ;colour select
mov cx,bytes ;bytes to send
int6:
push cx ;save count
mov al,[si] ;get character
inc si ;bump to next address
push si ;save current pointer
mov cx,1
mov ah,9
int 10H ;write char with attribute
mov ah,3
int 10H ;read cursor position
inc dl ;bump by 1 column
mov ah,2
int 10H ;set cursor position
pop si ;recover current pointer
pop cx ;recover count
loop int6
mov dx,old_cursor
mov bh,page_no
mov ah,2
int 10H ;reset old cursor position
int7:
pop bp ;restore registers
pop di
pop si
pop ES
pop dx
pop cx
pop bx
cli ;restore SP and SS
mov ax,old_SS
mov SS,ax
mov sp,old_SP
sti
int8:
popf ;recover flags
pop DS ;and regs
pop ax
jmp dword ptr CS:oldint08
newint08 endp
;
;----------------------------------------------------------------
;++++ Test to see if display of clock wanted
; Returns CARRY flag set if wanted
;
display_check proc near
push ax
push bx
cmp no_display_flag,'-' ;test display flag
je dc_off
cmp bios_flag,0 ;in bios?
jne dc_off ;not allowed if it is
disp_1:
mov ah,15 ;get video mode
int 10H
mov page_no,bh ;save current page
cmp al,2 ;see if mode 2
je dc_on
cmp al,3 ;or mode 3
je dc_on
cmp al,7 ;or mode 7
je dc_on
dc_off:
pop bx
pop ax
clc
ret
dc_on:
pop bx
pop ax
stc
ret
display_check endp
;
;----------------------------------------------------------------
;++++ Test for alarm pointed by bx
;
alarm_test proc near
cmp ax,alarm_times[bx] ;compare result with alarm time
jne alarm_test_2
push ax ;save alarm time
call dbl_beep ;alarm double beep
mov al,beeps ;load beeps
dec al ;decrement
mov beeps,al ;and save
cmp al,0 ;see if zero yet
jnz alarm_test_1 ;skip if not
mov beeps,beep_count
mov ax,0FFFFh ;reset alarm time to max
mov alarm_times[bx],ax ;to prevent retrigger
alarm_test_1:
xor ax,ax ;set zero flag
pop ax ;recover current minutes
alarm_test_2:
ret
alarm_test endp
;
;----------------------------------------------------------------
;++++ Produces double beep for alarm
;
dbl_beep proc near
call beep ;first beep
push cx
mov cx,beep_length ;timeout loop
dbl1:
dec al
jnz dbl1 ;extra delay
loop dbl1 ;inter-beep delay
pop cx
call beep ;second beep
ret
dbl_beep endp
;
;----------------------------------------------------------------
;++++ Beep generator
; Directly accesses sound generator timer in 8253
;
beep proc near
push ax
push cx
mov al,0B6H ;select timer #2
out 43H,al
mov ax,freq ;pick up timer count
out 42H,al ;low byte
mov al,ah
out 42H,al ;high byte
in al,61H ;get control word
push ax
or al,3 ;start timer
out 61H,al
mov cx,beep_length ;beep length constant
beep1:
dec al
jnz beep1
loop beep1 ;time delay for ON
pop ax
out 61H,al ;restore timer OFF
pop cx
pop ax
ret
beep endp
;
;----------------------------------------------------------------
;
end_resident equ $
;
;****************************************************************
;
;++++ END OF RESIDENT CODE
;
;****************************************************************
page
;****************************************************************
;++++ Initialization code
; Tests for already loaded code.
; If not present, installs code first.
; Then proceeds to decode command line.
;
initialize proc near
not word ptr start
xor bx,bx
mov ax,CS
next_segment:
inc bx
cmp ax,bx
mov ES,bx
jz not_installed
mov si,offset start
mov di,si
mov cx,msg_size
repz cmpsb
or cx,cx
jnz next_segment
call scan ;scan command line
mov al,err_code ;get error code
mov ah,4cH
int 21H ;exit program
;
not_installed:
mov ax,3510H ;save old interrupt 10H vector
int 21H
mov word ptr oldint10,bx
mov word ptr oldint10[2],es
mov ax,2510H ;then set the new 10H vector
mov dx,offset vidint
int 21H
mov ax,3508H ;save old interrupt 08H vector
int 21H
mov word ptr oldint08,bx
mov word ptr oldint08[2],es
mov ax,2508H ;then set the new 08H vector
mov dx,offset newint08
int 21H
push CS ;make ES=CS
pop ES
call scan ;scan command line
mov dx,offset msg7
call print ;send message to advise now resident
mov dx,offset end_resident ;last address to save
mov cl,4
shr dx,cl ;make into pages
inc dx ;plus 1
mov al,err_code ;get error code
mov ah,31H
int 21H ;terminate but stay resident
initialize endp
;
;----------------------------------------------------------------
;++++ Scan command line starting at 0080h
; Looks for control bytes and/or time code of form 'hh:mm'
;
scan proc near
mov alarms,0 ;alarms done count
xor ax,ax ;AX=current minutes store
xor bx,bx
xor dx,dx ;DH=':' field counter
mov di,0FFFFh ;DI=minutes store
mov ES:beeps,beep_count ;preset beep counter
mov si,offset dbuff ;point to start of string area
mov bl,[si] ;get string length byte
inc si
mov byte ptr [si+bx],al ;end of string set to zero
;
;++++ Character scanner loop
;
scan1:
call getchar ;get a character
jnz scan1a
jmp all_done ;exit if all done
scan1a:
cmp bl,' ' ;test for space
jb scan1 ;skip over control characters
je space_found ;space found
cmp bl,'?' ;test for '?' option
jne scan1b
;
;++++ help message requested - ignore all other functions
;
mov dx,offset helpmsg
call print
ret
;
;++++ Test now for '-'
;
scan1b:
cmp bl,'-' ;test for '-' option
jne scan1c ;skip if not
mov ES:no_display_flag,bl ;set up flag
jmp short scan1
;
;++++ Test now for '+'
;
scan1c:
cmp bl,'+' ;test for '+' option
jne scan1d ;skip if not
mov ES:no_display_flag,bl ;set up flag
jmp short scan1
;
;++++ Test now for 'x'
;
scan1d:
cmp bl,'X' ;test for 'x' option
jne scan1e ;skip if not
push ax
mov ax,ES:beep_length ;get beep length
shr ax,1 ;halve it
add ES:beep_length,ax ;beep length time increased 50%
pop ax
jmp short scan1
;
;++++ Test now for '*'
;
scan1e:
cmp bl,'*' ;test for '*' option
jne scan2 ;skip if not
mov alarms,0 ;alarms done count
xor ax,ax ;AX=current minutes store
xor bx,bx
xor dx,dx ;DH=':' field counter
mov di,0FFFFh ;DI=minutes store
mov cx,max_alarms
clear_1:
mov ES:alarm_times[bx],di ;clear alarm minutes store
add bx,2 ;next store
loop clear_1
jmp short scan1
;
;++++ Test now for ':' time delimiter
;
scan2:
cmp bl,':' ;test for separator
jnz scan3 ;skip if not
inc dh ;bump field count
cmp dh,2 ;see if 2 ':' chars received
jae time_1 ;error if found
push dx
mov cx,60 ;multiply hours by 60
mul cx
pop dx ;recover regs
mov di,ax ;save hours*60
mov ax,0 ;clear counter again
jmp short scan4
space_found:
cmp di,0ffffH ;see if anything done yet
je time_5 ;skip if not
cmp dh,1 ;see if timer was being processed
jne time_1
add ax,di ;add minutes to count
cmp ax,1440 ;see if overflow
jb time_2
time_1:
mov dx,offset msg1 ;error message
mov err_code,2
jmp time_msg
time_2:
mov bx,alarms ;get current alarms
cmp bx,max_alarms ;see if too many
jb time_3
mov dx,offset msg4 ;too many alarms
mov err_code,1
jmp time_msg
time_3:
add bx,bx ;make count into pointer
cmp ES:alarm_times[bx],0FFFFh ;see if free
je time_4
inc alarms ;bump alarms count
jmp time_2
time_4:
mov ES:alarm_times[bx],ax ;save alarm minutes count
inc alarms ;update alarms counter
time_5:
xor ax,ax ;clear running sum
mov di,0ffffH ;initialize minutes counter
xor dx,dx ;clear ':' conter
jmp scan1 ;try next count
;
;++++ Must be 0-9 or else will be ignored
;
scan3:
cmp bl,'0' ;test for ASCII '0'-'9'
jb bad_char
cmp bl,'9'
ja bad_char
sub bl,'0' ;make into binary digit
push dx
mov cx,10
mul cx ;multiply running sum by 10
add ax,bx ;add in new digit
pop dx
cmp ax,59 ;see if overflow
ja time_1 ;out of range
scan4:
jmp scan1 ;loop for next char
bad_char:
mov dx,offset msg5
mov err_code,3
jmp time_msg
;
;++++ scan complete
;
all_done:
cmp di,0ffffH ;see if new time specified
je scan7 ;skip if not
dec si ;back up over EOT byte
jmp space_found ;process data as though delimiter
;
time_msg:
call print ;print error message
scan7:
mov dx,offset msg6 ;assume display is set
cmp ES:no_display_flag,'-' ;test for no display
jne scan8
mov dx,offset msg3 ;print message
scan8:
call print
call show_times ;show times
ret ;return
scan endp
;
;----------------------------------------------------------------
;++++ Get character from input buffer
;++++ Convert to upper case if necessary
; Place in BL and set zero flag if BL=0
;
getchar proc near
mov bl,[si] ;get character
inc si ;bump string pointer
cmp bl,'a' ;below 'a' test
jb getchar_1
cmp bl,'z' ;above 'z' test
ja getchar_1
sub bl,20h ;make Upper Case
getchar_1:
or bl,bl ;test for zero
ret
getchar endp
;
;----------------------------------------------------------------
;++++ send character to CON:
;
charout proc near
push ax ;save ax
mov ah,2 ;set up command
int 21H ;send character in DL
pop ax ;recover ax
ret
charout endp
;
;----------------------------------------------------------------
;++++ Print string to user
;
print proc near
push ax ;save ax
mov ah,9 ;set up command
int 21H ;print string ending with '$'
pop ax ;recover ax
ret
print endp
;
;----------------------------------------------------------------
;
show_times proc near
mov cx,max_alarms ;maximum alarms allowed
mov bx,0 ;start at first alarm
mov msg2,'0'
show_time_1:
mov ax,ES:alarm_times[bx] ;get alarm time
cmp ax,0FFFFh ;see if cleared
je show_time_5
inc msg2 ;bump alarm counter
mov dx,0 ;hi word zero
div div60 ;convert to hh:mm
push dx ;save remainder (minutes)
call show_number ;show hours
mov dl,':'
call charout
pop ax
call show_number ;show minutes
mov dl,' '
call charout ;couple of spaces
call charout
show_time_5:
add bx,2 ;bump pointer
loop show_time_1
call crlf
mov dx,offset msg2 ;total alarms set
call print
ret
div60 dw 60
show_times endp
;
;----------------------------------------------------------------
;++++ display number in AL as two decimal digits
;
show_number proc near
xor ah,ah ;clear hi byte
div div10 ;divide by 10
add ax,'00' ;make ASCII
push ax ;save result
mov dl,al
call charout ;print 10s digit
pop ax
mov dl,ah
call charout ;print 1s digit
ret
div10 db 10
show_number endp
;
;----------------------------------------------------------------
;++++ Send CRLF to console
;
crlf proc near
push dx
mov dl,CR
call charout
mov dl,LF
call charout
pop dx
ret
crlf endp
;
;----------------------------------------------------------------
;
err_code db 0 ;error code for DOS return
alarms dw 0 ;current alarm counter
;
helpmsg db CR,LF,'******* CLOCKON V2.01e',BETA,'*******',CR,LF
db 'Command format is CLOCKON [+|-] [x] [*] [hh:mm .... ]',CR,LF
db TAB,'where + enables clock display',CR,LF
db TAB,' - inhibits clock display',CR,LF
db TAB,' x extends alarm sounds',CR,LF
db TAB,' * clears all current alarms',CR,LF
db TAB,' hh:mm sets alarm times (up to 9)',CR,LF,'$'
msg1 db bel,'ERROR: Invalid time. Range is 00:00 to 23:59',CR,LF,'$'
msg2 db '0 alarm(s) set.',CR,LF,'$'
msg3 db 'Clock display is inhibited.',CR,LF,'$'
msg6 db 'Clock display is enabled.',CR,LF,'$'
msg4 db bel,'WARNING: Only 9 alarms allowed.',CR,LF,'$'
msg5 db bel,'ERROR: Illegal character in command.',CR,LF,'$'
msg7 db 'CLOCKON is now resident.',CR,LF,'$'
code ends
;
end start